<?php


namespace Aoe\Emulator\Schema;


use Aoe\Emulator\Ifc\Type;
use Aoe\Emulator\Ifc\Key;
use Aoe\Emulator\Schema\Element\Element;
use Aoe\Emulator\Schema\Element\Elements;
use Aoe\Emulator\Schema\Element\Relation;
use Exception;
use Iterator;

/**
 * # 模型
 */
class Model extends Micro
{
    /**
     * 树结构
     */
    const string TREE    = 'tree';
    /**
     * 集合数据表
     */
    const string TABLE   = 'table';
    /**
     * 关键字段名
     */
    const string KEY      = 'key';
    /**
     * 索引字段名
     */
    const string INDEX     = 'index';
    /**
     * 使用Json存储
     */
    const string JSON     = 'json';
    /**
     * 扩展模型
     */
    const string EXTEND   = 'extend';
    
    /**
     * @var ?Elements
     */
    protected ?Elements $elementGroup = null;
    
    public function __construct(
        array            $def,
        string           $name,
        /**
         * @var Models 所属的集合组
         */
        protected(set) Models $group {
            get {
                return $this->group;
            }
        }
    )
    {
        parent::__construct($def, $name);
    }
    
    public function hasElement(string $name): bool
    {
        return $this->getElements()->has($name);
    }
    
    public function getElements(): Elements
    {
        if ($this->elementGroup === null) {
            $this->elementGroup = new Elements($this->get(Key::ELEMENTS, []), $this);
        }
        
        return $this->elementGroup;
    }

    /**
     * @param array|null $elements
     *
     * @return Iterator<int, Element>
     */
    public function getElementIterator(array | null $elements = null): Iterator
    {
        return $this->getElements()->getIterator($elements);
    }
    
    /**
     * @param string $name
     *
     * @return Element | Relation
     * @throws Exception
     */
    public function getElement(string $name): Element | Relation
    {
        return $this->getElements()->get($name);
    }
    
    /**
     * @throws Exception
     */
    public function getModel(string $name): Model
    {
        return $this->group->get($name);
    }

    public function isTree(): bool
    {
        return !!$this->get(self::TREE);
    }
    
    public function isUuid(): bool
    {
        return !!$this->get(Type::UUID);
    }
    
    public function useJson(): bool
    {
        return !!$this->get(self::JSON);
    }
    
    public function getTableName(): string
    {
        return strtolower($this->get(self::TABLE, $this->_default_table_name()));
    }
    
    /**
     * @return string 关联表描述字段的名称
     */
    public function getKey(): string
    {
        return $this->get(self::KEY, Key::NAME);
    }

    public function getIndex(): string
    {
        return $this->get(self::INDEX, Type::ID);
    }
    
    public function isExtend(): bool
    {
        return $this->get(self::EXTEND, false);
    }
    
    private function _default_table_name(): string
    {
        return TABLE_PREFIX. $this->group->name . '_' . $this->name;
    }
}